import asyncio
import time
from contextlib import asynccontextmanager

from fastapi import FastAPI, Request
from fastapi.openapi.docs import get_swagger_ui_html, get_swagger_ui_oauth2_redirect_html
from fastapi.staticfiles import StaticFiles
from starlette.middleware.cors import CORSMiddleware
from starlette.middleware.gzip import GZipMiddleware
from starlette.responses import JSONResponse

from app.api import token_router, user_router, book_router, shelf_router, user_reading_progress_router, captcha_router
from app.core.config import SETTING
from app.core.error_handler import CustomException
from app.middleware import RateLimitMiddleware
from app.middleware.logging import logger
from app.models.response_model import ResponseCode


@asynccontextmanager
async def life_span(app: FastAPI):
    from app.services.recommend_service import book_recommend_service
    from app.services.right_service import RightService
    await asyncio.gather(
        book_recommend_service.load_model(),
        RightService.prepare_info(),
    )
    yield


# 在 main.py 中注册
app = FastAPI(
    docs_url=None,
    lifespan=life_span
)

# 挂载静态文件目录
app.mount("/static", StaticFiles(directory="static"), name="static")

# 开发环境允许的源（包括本地）
DEV_ORIGINS = [
    "http://localhost",
    "http://127.0.0.1",
    "http://100.64.81.35",
    "http://1.95.141.194"
]
app.add_middleware(GZipMiddleware, minimum_size=500)
app.add_middleware(
    CORSMiddleware,
    allow_origins=DEV_ORIGINS,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
    expose_headers=["x-captcha-id"],  # 暴露自定义头部
)
app.add_middleware(
    RateLimitMiddleware,
    calls=SETTING.IP_LIMIT_COUNT,
    period=SETTING.IP_LIMIT_WINDOW,
    exclude_paths={"/docs", "/openapi.json", "/health"}  # 排除 Swagger 等
)


# allow_origin_regex=r'$http://localhost\.*^',


@app.middleware('http')
async def log_middleware(request: Request, call_next):
    start_time = time.perf_counter()
    response = await call_next(request)
    process_time = time.perf_counter() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    logger.info(f"{request.client.host} {request.method} {request.url} {response.status_code} {process_time:.4f}s")
    return response


@app.exception_handler(CustomException)
async def custom_exception_handler(request: Request, exc: CustomException):
    return JSONResponse(
        status_code=exc.status_code,
        content={
            'code': ResponseCode.ERROR,
            'message': exc.message if exc.message else str(exc),
            'data': None
        }
    )


@app.exception_handler(Exception)
async def exception_handler(request: Request, exc: Exception):
    return JSONResponse(
        status_code=500,
        content={
            'code': ResponseCode.ERROR,
            'message': str(exc),
            'data': None
        }
    )


if SETTING.ENV != 'prod':
    @app.get("/docs", include_in_schema=False)
    async def custom_swagger_ui_html():
        return get_swagger_ui_html(
            openapi_url=app.openapi_url,
            title=app.title + " - Swagger UI",
            oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
            swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js",  # ← 国内能访问
            swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css",  # ← 国内能访问
        )


    @app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
    async def swagger_ui_redirect():
        return get_swagger_ui_oauth2_redirect_html()


@app.get("/")
async def root():
    return {"message": "Hello World"}


#  获取 token  路由
app.include_router(token_router)
# 用户相关
app.include_router(user_router)
# 书籍相关
app.include_router(book_router)
# 书架相关
app.include_router(shelf_router)
# 阅读历史相关
app.include_router(user_reading_progress_router)
#  验证码相关
app.include_router(captcha_router)
